home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / uupc11ys.zip / LIB / HOSTABLE.C < prev    next >
C/C++ Source or Header  |  1993-04-10  |  26KB  |  678 lines

  1. /*
  2.    h o s t a b l e . c
  3.  
  4.    Remote host table routines for UUPC/extended
  5.  
  6.    Copyright (C) 1989, 1990 by Andrew H. Derbyshire
  7.  
  8.    See file README.SCR for restrictions on re-distribution.
  9.  
  10.    History:
  11.  
  12.       18 Mar 1990 Create hostable.c from router.c                    ahd
  13.                   Move code to generate localdomain to here          ahd
  14.       22 Apr 90   Perform check for full host name before examining
  15.                   name without domain.                               ahd
  16.       29 Jul 90   Only load host table based on first six characters
  17.                   of host name.                                      ahd
  18.  */
  19.  
  20.  /*
  21.   *      $Id: HOSTABLE.C 1.5 1993/04/11 00:32:29 ahd Exp $
  22.   *
  23.   *      $Log: HOSTABLE.C $
  24.  *     Revision 1.5  1993/04/11  00:32:29  ahd
  25.  *     Global edits for year, TEXT, etc.
  26.  *
  27.  *     Revision 1.4  1993/04/04  04:57:01  ahd
  28.  *     Trap existence of local host name in SYSTEMS file
  29.  *
  30.  *     Revision 1.3  1992/12/18  12:05:57  ahd
  31.  *     Suppress duplicate machine state messages to improving OS/2 scrolling
  32.  *
  33.  *     Revision 1.3  1992/12/18  12:05:57  ahd
  34.  *     Suppress duplicate machine state messages to improving OS/2 scrolling
  35.  *
  36.  * Revision 1.2  1992/11/22  20:58:55  ahd
  37.  * Use strpool to allocate const strings
  38.  *
  39.   */
  40.  
  41. #include <ctype.h>
  42. #include <limits.h>
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <sys/types.h>
  47.  
  48. #include "lib.h"
  49. #include "hlib.h"
  50. #include "hostable.h"
  51. #include "security.h"
  52.  
  53. currentfile();
  54.  
  55. static struct HostTable *hosts = NULL;
  56.  
  57. static size_t  HostElements = 0;
  58.  
  59. static size_t loadhost( void );
  60.  
  61. static int hostcmp( const void *a , const void *b );
  62.  
  63. static size_t localdomainl;   /* Length of localdomain               */
  64.  
  65. /*--------------------------------------------------------------------*/
  66. /*    c h e c k n a m e                                               */
  67. /*                                                                    */
  68. /*    Perform a search for a single host name                         */
  69. /*                                                                    */
  70. /*    Rewritten for release 1.10a.  The old release had               */
  71. /*    most of the same logic, but nested it inside the search         */
  72. /*    loop; adding new cases (specifically, the wildcard domain       */
  73. /*    search) was difficult.  This version is slower because it       */
  74. /*    makes multiple passes through the host table, but this          */
  75. /*    isn't really performance code for a small (under 100 hosts)     */
  76. /*    table.                                 ahd 26 April 1991        */
  77. /*                                                                    */
  78. /*    Note because we save the arguments and use a static variable    */
  79. /*    to save the result of searches, this function is not            */
  80. /*    recursive!                                                      */
  81. /*--------------------------------------------------------------------*/
  82.  
  83. struct HostTable *checkname(const char *name)
  84. {
  85.    char  hostname[MAXADDR];   /* Local copy of name to process       */
  86.    char *period;              /* Pointer "." in hostname             */
  87.    size_t namel;              /* Length of the name input            */
  88.    size_t column;             /* Length of the name input            */
  89.  
  90.    static char savename[MAXADDR] = "";
  91.                               /* Saved copy of name to make function
  92.                                  reducible                           */
  93.    static struct HostTable *hostz;
  94.  
  95. /*--------------------------------------------------------------------*/
  96. /*                       Validate the argument                        */
  97. /*--------------------------------------------------------------------*/
  98.  
  99.    if ((name == NULL) || ((namel = strlen(name)) == 0))
  100.    {
  101.       printmsg(0,"checkname: Invalid (missing) hostname passed");
  102.       panic();
  103.       return NULL;           /* Never executed                      */
  104.    }
  105.  
  106. /*--------------------------------------------------------------------*/
  107. /*    If same argument as last time, return same result; otherwise    */
  108. /*    save input for next pass                                        */
  109. /*--------------------------------------------------------------------*/
  110.  
  111.    if (equal(name, savename))
  112.       return hostz;
  113.    strcpy( savename, name);   /* Save for next pass                  */
  114.  
  115. /*--------------------------------------------------------------------*/
  116. /*                      Search for the full name                      */
  117. /*--------------------------------------------------------------------*/
  118.  
  119.    if ((hostz = searchname(name, MAXADDR)) != BADHOST)
  120.       return hostz;
  121.  
  122. /*--------------------------------------------------------------------*/
  123. /*    If the name already has the local domain attached, search for   */
  124. /*    the host name without the domain.                               */
  125. /*--------------------------------------------------------------------*/
  126.  
  127.    column = namel - localdomainl;
  128.    if ((namel > localdomainl) && equal(E_localdomain, &name[column]) &&
  129.        (name[ column - 1] == '.'))
  130.    {
  131.       if ((hostz = searchname(name,column-1 )) != BADHOST)
  132.          return hostz;
  133.    } /* if */
  134.  
  135. /*--------------------------------------------------------------------*/
  136. /*              Search for the name in the local domain               */
  137. /*--------------------------------------------------------------------*/
  138.  
  139.    if ((namel + localdomainl + 2) < MAXADDR)
  140.    {
  141.       sprintf(hostname,"%s.%s",name,E_localdomain);
  142.       if ((hostz = searchname(hostname, MAXADDR)) != BADHOST)
  143.          return hostz;
  144.    } /* if */
  145.  
  146. /*--------------------------------------------------------------------*/
  147. /*    If a simple name and not found, return search for truncated     */
  148. /*    UNIX name.                                                      */
  149. /*--------------------------------------------------------------------*/
  150.  
  151.    if ( strchr(name,'.') == NULL )
  152.       return checkreal( name );
  153.  
  154. /*--------------------------------------------------------------------*/
  155. /*               Perform a wildcard domain name search                */
  156. /*--------------------------------------------------------------------*/
  157.  
  158.    period = (char *) name;    /* Begin at front of name              */
  159.    while( period != NULL )
  160.    {
  161.       sprintf( hostname,(*period == '.') ? "*%s" : "*.%s",period);
  162.                               /* We add the missing period for the
  163.                                  first pass through the loop         */
  164.       if ((hostz = searchname(hostname, MAXADDR)) != BADHOST)
  165.          return hostz;
  166.       period = strchr(++period,'.');   /* Not found, search for next
  167.                                           higher domain              */
  168.    }
  169.  
  170. /*--------------------------------------------------------------------*/
  171. /*         We didn't find the host.  Return failure to caller         */
  172. /*--------------------------------------------------------------------*/
  173.  
  174.    return BADHOST;
  175.  
  176. }  /* checkname */
  177.  
  178. /*--------------------------------------------------------------------*/
  179. /*    c h e c k r e a l                                               */
  180. /*                                                                    */
  181. /*    Perform a search for a real (connected) simple host name        */
  182. /*--------------------------------------------------------------------*/
  183.  
  184. struct HostTable *checkreal(const char *name)
  185. {
  186.    size_t  namel = max( strlen(name), HOSTLEN);
  187.    struct HostTable *hostp = searchname( name, namel );
  188.  
  189. /*--------------------------------------------------------------------*/
  190. /*             If we didn't find the host, return failure             */
  191. /*--------------------------------------------------------------------*/
  192.  
  193.    if ((hostp == BADHOST) || (hostp->hstatus >= nocall))
  194.       return hostp;           /* Return raw information              */
  195.    else
  196.       return BADHOST;         /* Not a real host, invalid for our
  197.                                  purposes                            */
  198.  
  199. } /* searchreal */
  200.  
  201. /*--------------------------------------------------------------------*/
  202. /*    s e a r c h n a m e                                             */
  203. /*                                                                    */
  204. /*    Look up a system name in our systems (L.sys) file.              */
  205. /*    Only the first 7 characters of a system name is significant.    */
  206. /*--------------------------------------------------------------------*/
  207.  
  208. struct HostTable *searchname(const char *name, const size_t namel)
  209. {
  210.    int   lower;
  211.    int   upper;
  212.  
  213.  /*------------------------------------------------------------------*/
  214.  /*             Initialize the host name table if needed             */
  215.  /*------------------------------------------------------------------*/
  216.  
  217.    if (HostElements == 0)           /* host table initialized yet?   */
  218.       HostElements = loadhost();        /* No --> load it            */
  219.  
  220.    lower = 0;
  221.    upper = HostElements - 1;
  222.    while ( lower <= upper )
  223.    {
  224.       int midpoint = (lower + upper) / 2;
  225.       int hit;
  226.  
  227. /*--------------------------------------------------------------------*/
  228. /*    Compare for up to the specified length of the host name, but    */
  229. /*    never less than the length of the item we are comparing it      */
  230. /*    to.  In other words, the search key can be shorter than the     */
  231. /*    table entry for a simple host name.                             */
  232. /*                                                                    */
  233. /*    This mostly affects simple host names, as domain names          */
  234. /*    have a Very Large Number (VLN) passed into to insure we         */
  235. /*    compare the entire length of the name.                          */
  236. /*--------------------------------------------------------------------*/
  237.  
  238.       hit = strnicmp(name,hosts[midpoint].hostname,namel);
  239.       if (hit > 0)
  240.          lower = midpoint + 1;
  241.       else if ((hit < 0) || (strlen(hosts[midpoint].hostname) > namel))
  242.          upper = midpoint - 1;
  243.       else {
  244.             printmsg(8,"searchname: Looking for \"%s\" of length %d,\
  245.  found \"%s\"",
  246.             name, namel, hosts[midpoint].hostname);
  247.          return &hosts[midpoint];
  248.       }
  249.    }
  250.  
  251. /*--------------------------------------------------------------------*/
  252. /*         We didn't find the host.  Return failure to caller         */
  253. /*--------------------------------------------------------------------*/
  254.  
  255.    printmsg(8,"searchname: Looking for \"%s\", did not find it",
  256.             name);
  257.    return BADHOST;
  258.  
  259. }  /* searchname */
  260.  
  261.  
  262. /*--------------------------------------------------------------------*/
  263. /*    n e x t h o s t                                                 */
  264. /*                                                                    */
  265. /*    Returns next host in table with requested attribute             */
  266. /*--------------------------------------------------------------------*/
  267.  
  268. struct HostTable *nexthost( const boolean start )
  269. {
  270.    static size_t current = 0;
  271.  
  272.    if (HostElements == 0)     /* host table initialized yet?         */
  273.       HostElements = loadhost(); /* No --> load it                   */
  274.  
  275.    if (start)
  276.       current = 0;
  277.    else
  278.       current ++;
  279.  
  280.    while ( current < HostElements )
  281.    {
  282.       if (hosts[current].hstatus >= nocall)
  283.          return &hosts[current];
  284.       else
  285.          current++;
  286.    }
  287.  
  288.    return BADHOST;
  289.  
  290. }  /* nexthost */
  291.  
  292.  
  293. /*--------------------------------------------------------------------*/
  294. /*    i n i t h o s t                                                 */
  295. /*                                                                    */
  296. /*    Intializes a host table entry for for loadhost                  */
  297. /*--------------------------------------------------------------------*/
  298.  
  299. struct HostTable *inithost(char *name)
  300. {
  301.  
  302.    size_t hit = HostElements;
  303.    size_t element = 0;
  304.    static size_t max_elements = 32; /* This is automatically
  305.                                        raised if we run out of room  */
  306.  
  307.    if (hosts == NULL)
  308.    {
  309.       hosts = calloc(max_elements, sizeof(*hosts));
  310.       printmsg(5,"inithost: Allocated room for %d host entries",
  311.                max_elements);
  312.    }
  313.    else if ( max_elements == HostElements )
  314.    {
  315.       max_elements = max_elements * 2;
  316.       hosts = realloc(hosts , max_elements * sizeof(*hosts));
  317.       printmsg(5,"inithost: reallocated room for %d host entries",
  318.                max_elements);
  319.    }
  320.    checkref(hosts);
  321.  
  322. /*--------------------------------------------------------------------*/
  323. /*    Add the host to the table.  Note that we must add the host      */
  324. /*    to the table ourselves (rather than use lsearch) because we     */
  325. /*    must make a copy of the string; the *token we use for the       */
  326. /*    search is in the middle of our I/O buffer!                      */
  327. /*--------------------------------------------------------------------*/
  328.  
  329.    while ( element < hit )
  330.    {
  331.       if (equali( hosts[element].hostname , name ))
  332.          hit = element;
  333.       else
  334.          element++;
  335.    }
  336.  
  337. /*--------------------------------------------------------------------*/
  338. /*               If a new element, initialize the block               */
  339. /*--------------------------------------------------------------------*/
  340.  
  341.    if (hit == HostElements)
  342.    {
  343.       memset( &hosts[hit] , 0, sizeof hosts[hit] );
  344.       hosts[hit].hostname = newstr(name);
  345.       checkref( hosts[hit].hostname );
  346.       hosts[hit].anylogin = TRUE;   /* Allow generic login by default   */
  347.       HostElements ++ ;
  348.    } /* if */
  349.  
  350.    return &hosts[hit];
  351.  
  352. } /* inithost */
  353.  
  354. /*--------------------------------------------------------------------*/
  355. /*    l o a d h o s t                                                 */
  356. /*                                                                    */
  357. /*    Initializes table of known host names for checkname             */
  358. /*--------------------------------------------------------------------*/
  359.  
  360. static size_t loadhost()
  361. {
  362.    FILE *ff;
  363.    char buf[BUFSIZ];
  364.    char *token;
  365.    char s_systems[FILENAME_MAX]; /* full-name of systems file        */
  366.    size_t hit;
  367.  
  368.    struct HostTable *hostp;
  369.  
  370. /*--------------------------------------------------------------------*/
  371. /*                      Validate the domain name                      */
  372. /*--------------------------------------------------------------------*/
  373.  
  374.    token = strrchr(E_domain,'.');
  375.  
  376.    if (token == NULL)
  377.    {
  378.       printmsg(0,"Domain name \"%s\" is invalid, missing period",E_domain);
  379.       panic();
  380.    }
  381.  
  382. /*--------------------------------------------------------------------*/
  383. /*                  Load the local host information                   */
  384. /*--------------------------------------------------------------------*/
  385.  
  386.    hostp = inithost(E_nodename);
  387.    hostp->hstatus  = localhost;
  388.    hostp->realname = E_nodename; /* Don't let user alias our system
  389.                                     name                             */
  390.  
  391. /*--------------------------------------------------------------------*/
  392. /*                Now do the local domain information                 */
  393. /*--------------------------------------------------------------------*/
  394.  
  395.    hostp = inithost(E_domain);
  396.  
  397.    if (hostp->via == NULL )   /* Not initialized?                    */
  398.       hostp->via      = E_nodename;  /* Correct --> Route via local  */
  399.    else
  400.       panic();                /* "Houston, we a have problem" -
  401.                                  Apollo 13                           */
  402.  
  403.    hostp->realname = E_nodename;
  404.  
  405. /*--------------------------------------------------------------------*/
  406. /*    If we allow anonymous UUCP, load the dummy host we use for      */
  407. /*    connections to such hosts                                       */
  408. /*--------------------------------------------------------------------*/
  409.  
  410.    if ( E_anonymous != NULL )
  411.    {
  412.       hostp = inithost( ANONYMOUS_HOST );
  413.       hostp->hstatus = nocall;
  414.       hostp->via     = E_nodename;
  415.       hostp->hstats  = malloc( sizeof *(hostp->hstats) );
  416.       checkref( hostp->hstats );
  417.       memset( hostp->hstats, 0, sizeof *(hostp->hstats) );
  418.    } /* if */
  419.  
  420. /*--------------------------------------------------------------------*/
  421. /*                  Load names from the systems file                  */
  422. /*--------------------------------------------------------------------*/
  423.  
  424.    mkfilename(s_systems, E_confdir, SYSTEMS);
  425.  
  426.    ff = FOPEN(s_systems, "r",TEXT_MODE);
  427.    if (ff == NULL)
  428.    {
  429.       printerr(s_systems);
  430.       panic();
  431.    }
  432.  
  433.    while (! feof(ff))
  434.    {
  435.       if (fgets(buf,BUFSIZ,ff) == NULL)   /* Try to read a line      */
  436.          break;                  /* Exit if end of file              */
  437.       token = strtok(buf,WHITESPACE);
  438.       if (token == NULL)         /* Any data?                        */
  439.          continue;               /* No --> read another line         */
  440.       if (token[0] == '#')
  441.          continue;                  /* Line is a comment; loop again */
  442.  
  443.       if ( equal( token, E_nodename ))
  444.       {
  445.          printmsg(0,"Error: Local host %s must not be in SYSTEMS file",
  446.                     E_nodename );
  447.          panic();
  448.       }
  449.  
  450.       hostp = inithost(token);
  451.  
  452.       if (hostp->hstatus == phantom)
  453.       {
  454.          hostp->hstatus = nocall;
  455.          hostp->hstats  = malloc( sizeof *(hostp->hstats) );
  456.          checkref( hostp->hstats );
  457.          memset( hostp->hstats, 0, sizeof *(hostp->hstats) );
  458.       }
  459.    } /* while */
  460.  
  461.    fclose(ff);
  462.  
  463. /*--------------------------------------------------------------------*/
  464. /*               Now the load the routing file, if any.               */
  465. /*--------------------------------------------------------------------*/
  466.  
  467.    mkfilename(s_systems, E_confdir, PATHS);
  468.  
  469.    if ((ff = FOPEN(s_systems, "r",TEXT_MODE)) != NULL)
  470.    {
  471.  
  472.       while (! feof(ff))
  473.       {
  474.          boolean freeit = FALSE;
  475.  
  476.          if (fgets(buf,BUFSIZ,ff) == NULL)   /* Try to read a line      */
  477.             break;                  /* Exit if end of file              */
  478.          token = strtok(buf,WHITESPACE);
  479.  
  480.          if (token == NULL)         /* Any data?                        */
  481.             continue;               /* No --> read another line         */
  482.  
  483.          if (*token == '#')
  484.             continue;               /* Line is a comment; loop again    */
  485.  
  486.          hostp = inithost(token);
  487.          token = strtok(NULL,WHITESPACE);
  488.  
  489.          if ( token == NULL )
  490.          {
  491.             printmsg(0,"loadhost: Missing path name for host \"%s\"",
  492.                         hostp->hostname);
  493.             freeit = TRUE;
  494.          }
  495. /*--------------------------------------------------------------------*/
  496. /*                              Gate way                              */
  497. /*--------------------------------------------------------------------*/
  498.          else if (equal(token,"|"))
  499.          {
  500.             token = strtok(NULL,"\n");
  501.  
  502.             if (( hostp->via != NULL ) || ( token == NULL ))
  503.                freeit = TRUE;
  504.             else {
  505.                hostp->hstatus = gatewayed;
  506.  
  507.                while(isspace( *token ))   /* Drop leading white space only */
  508.                   token++;
  509.  
  510.                if (*token == '\0')        /* Empty string?           */
  511.                   freeit = TRUE;          /* Yes --> Flag for error  */
  512.                else
  513.                   hostp->via = token = newstr(token);
  514.             } /* else if */
  515.  
  516.             if ( freeit )
  517.                printmsg(0,"loadhost: Invalid/duplicate gateway for \"%s\"",
  518.                      hostp->hostname );
  519.  
  520.          } /* else if */
  521. /*--------------------------------------------------------------------*/
  522. /*                               Alias                                */
  523. /*--------------------------------------------------------------------*/
  524.          else if (equal(token,"="))
  525.          {
  526.             token = strtok(NULL,WHITESPACE);
  527.  
  528.             if (( hostp->realname == NULL ) && (token != NULL))
  529.                hostp->realname = token = newstr( token );
  530.             else {
  531.                printmsg(0,"loadhost: Invalid/duplicate alias of \"%s\"",
  532.                      hostp->hostname );
  533.                freeit = TRUE;
  534.             } /* else */
  535.          } /* else if (equal(token,"=")) */
  536. /*--------------------------------------------------------------------*/
  537. /*                           Routing entry                            */
  538. /*--------------------------------------------------------------------*/
  539.          else {
  540.  
  541.             if ( hostp->via == NULL )
  542.                hostp->via = token = newstr( token );
  543.             else {
  544.                printmsg(0,"loadhost: Invalid/duplicate route for \"%s\"",
  545.                      hostp->hostname );
  546.                freeit = TRUE;
  547.             } /* else */
  548.  
  549.          } /* else */
  550.  
  551.  
  552.          if ( ! freeit )
  553.          {
  554.             checkref( token );
  555.  
  556.             if (*token == '*')       /* Wildcard on right side?    */
  557.             {
  558.                printmsg(0,
  559.      "loadhost: Wildcard \"%s\" not allowed for real name of host \"%s\"",
  560.          token, hostp->hostname);
  561.                freeit = TRUE;
  562.             } /* if (*token == '*') */
  563.          } /* if ( ! freeit ) */
  564.  
  565.          if ( freeit )
  566.          {
  567.             if ( hostp->hstatus == phantom )
  568.                HostElements--;            /* Ignore the routing entry   */
  569.          }
  570.       }  /* end while */
  571.  
  572.       fclose(ff);
  573.    }
  574.    else {
  575.       if ( debuglevel > 2 )
  576.          perror( s_systems );
  577.    }
  578.  
  579. /*--------------------------------------------------------------------*/
  580. /*                   Provide default for fromdomain                   */
  581. /*--------------------------------------------------------------------*/
  582.  
  583.    if (E_fdomain != NULL)     /* If fromdomain provided ...          */
  584.    {
  585.       hostp = inithost(E_fdomain);
  586.  
  587.       if (hostp->via == NULL)    /* Uninitialized?                   */
  588.          hostp->via = E_mailserv;   /* Yes --> Use default route     */
  589.    }
  590.    else
  591.       E_fdomain = E_domain;   /* Use domain as fromdomain            */
  592.  
  593. /*--------------------------------------------------------------------*/
  594. /*    Shrink the table to whatever we actually need, then sort it     */
  595. /*--------------------------------------------------------------------*/
  596.  
  597.    hosts = realloc(hosts, HostElements *  sizeof(*hosts));
  598.    checkref(hosts);
  599.  
  600.    qsort(hosts, HostElements ,sizeof(hosts[0]) , hostcmp);
  601.  
  602. /*--------------------------------------------------------------------*/
  603. /*    If the user did not define a local domain, then generate one    */
  604. /*    based on our own domain name; the generated name will either    */
  605. /*    be of the format ".a.b.c" (incuding the trailing period) or     */
  606. /*    a null string.                                                  */
  607. /*--------------------------------------------------------------------*/
  608.  
  609.    if ( E_localdomain == NULL )
  610.    {
  611.       E_localdomain = strchr(E_domain,'.');
  612.  
  613.       if (E_localdomain == NULL)
  614.          E_localdomain = "UUCP";
  615.       else {
  616.          E_localdomain ++;    /* Step past the period                */
  617.  
  618.          if ( !equal(E_localdomain, "UUCP" ) &&
  619.               (strchr( E_localdomain, '.' ) == NULL ))
  620.                               /* Implied single level domain name?   */
  621.             E_localdomain = E_domain;
  622.                               /* Impossible, use both parts of name  */
  623.       } /* else */
  624.  
  625.       printmsg(3,"loadhost: local domain defined as \"%s\"",
  626.                  E_localdomain);
  627.  
  628.    } /* if */
  629.  
  630.    localdomainl = strlen(E_localdomain);
  631.  
  632. /*--------------------------------------------------------------------*/
  633. /*    Amend for the sin of typing the domain wrong in the sample      */
  634. /*    files for the old releases of UUPC/extended.                    */
  635. /*--------------------------------------------------------------------*/
  636.  
  637.    if (equal(E_localdomain,"UUPC"))
  638.    {
  639.       printmsg(0,"inithost: UUPC is an invalid domain name! "
  640.                  "Change it to UUCP");
  641.       panic();
  642.    }
  643.  
  644. /*--------------------------------------------------------------------*/
  645. /*                      Display the final table                       */
  646. /*--------------------------------------------------------------------*/
  647.  
  648.    for (hit = 0; hit < HostElements; hit++)
  649.    {
  650.       printmsg(8,"loadhost: entry[%02d] %-20s\tvia %s\talias %s",
  651.                   hit,
  652.                   hosts[hit].hostname,
  653.                   (hosts[hit].via == NULL) ? "(self)" : hosts[hit].via,
  654.                   (hosts[hit].realname == NULL)
  655.                                     ? "(self)" : hosts[hit].realname);
  656.    } /* for */
  657.  
  658. /*--------------------------------------------------------------------*/
  659. /*                          Return to caller                          */
  660. /*--------------------------------------------------------------------*/
  661.  
  662.    return (HostElements) ;
  663. } /*loadhost*/
  664.  
  665.  
  666. /*--------------------------------------------------------------------*/
  667. /*    h o s t c m p                                                   */
  668. /*                                                                    */
  669. /*    Accepts indirect pointers to two strings and compares           */
  670. /*    them using stricmp (case insensitive string compare)            */
  671. /*--------------------------------------------------------------------*/
  672.  
  673. int hostcmp( const void *a , const void *b )
  674. {
  675.    return stricmp(((struct HostTable*) a)->hostname,
  676.         ((struct HostTable*) b)->hostname);
  677. }  /*hostcmp*/
  678.